
class TypeBuilder
      extend T::Sig

      sig { void }
      def initialize
          @registry = T.let(Baml::Ffi::TypeBuilder.new, Baml::Ffi::TypeBuilder)
          @classes = T.let(Set["Example", "Example2"], T::Set[String])
          @enums = T.let(Set[], T::Set[String])
      end

      sig { returns(Baml::Ffi::TypeBuilder) }
      def _registry
          @registry
      end

      sig { returns(Baml::Ffi::FieldType) }
      def string
          @registry.string
      end

      sig { returns(Baml::Ffi::FieldType) }
      def int
          @registry.int
      end

      sig { returns(Baml::Ffi::FieldType) }
      def float
          @registry.float
      end

      sig { returns(Baml::Ffi::FieldType) }
      def bool
          @registry.bool
      end

      sig { params(inner_type: Baml::Ffi::FieldType).returns(Baml::Ffi::FieldType) }
      def list(inner_type)
          @registry.list(inner_type)
      end

      sig { returns(Baml::Ffi::FieldType) }
      def null
          @registry.null
      end

      sig { params(key_type: Baml::Ffi::FieldType, value_type: Baml::Ffi::FieldType).returns(Baml::Ffi::FieldType) }
      def map(key_type, value_type)
          @registry.map(key_type, value_type)
      end

      sig { params(types: T::Array[Baml::Ffi::FieldType]).returns(Baml::Ffi::FieldType) }
      def union(types)
          @registry.union(types)
      end

      sig { params(name: String).returns(ClassBuilder) }
      def add_class(name)
          if @classes.include?(name)
              raise "Class with name #{name} already exists."
          end
          if @enums.include?(name)
              raise "Enum with name #{name} already exists."
          end
          @classes.add(name)
          ClassBuilder.new(@registry, name)
      end

      sig { params(name: String).returns(EnumBuilder) }
      def add_enum(name)
          if @classes.include?(name)
              raise "Class with name #{name} already exists."
          end
          if @enums.include?(name)
              raise "Enum with name #{name} already exists."
          end
          @enums.add(name)
          EnumBuilder.new(@registry, name)
      end

      sig { params(baml: String).void }
      def add_baml(baml)
          @registry.add_baml(baml, Baml::Internal::DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOU_RE_DOING_RUNTIME)
      end

      class ClassBuilder
          extend T::Sig

          sig { params(registry: Baml::Ffi::TypeBuilder, name: String, properties: T.nilable(T::Set[String])).void }
          def initialize(registry, name, properties = nil)
              @builder = T.let(registry.class_(name), Baml::Ffi::ClassBuilder)
              @properties = T.let(properties == nil ? Set.new : properties, T::Set[String])
          end

          sig { returns(Baml::Ffi::FieldType) }
          def type
              @builder.field
          end

          sig { params(name: String, type: Baml::Ffi::FieldType).returns(Baml::Ffi::FieldType) }
          def add_property(name, type)
              if @properties.include?(name)
                  raise "Property #{name} already exists."
              end
              @properties.add(name)
              @builder.property(name).type(type)
          end
      end

      class EnumBuilder
          extend T::Sig

          sig { params(registry: Baml::Ffi::TypeBuilder, name: String, values: T.nilable(T::Set[String])).void }
          def initialize(registry, name, values = nil)
              @builder = T.let(registry.enum(name), Baml::Ffi::EnumBuilder)
              @values = T.let(values == nil ? Set.new : values, T::Set[String])
          end

          sig { returns(Baml::Ffi::FieldType) }
          def type
              @builder.field
          end

          sig { params(name: String).returns(Baml::Ffi::FieldType) }
          def add_value(name)
              if @values.include?(name)
                  raise "Value #{name} already exists."
              end
              @values.add(name)
              @builder.value(name)
          end
      end

    {% for cls in classes if cls.dynamic %}
    def {{cls.name}}
        ClassBuilder.new(@registry, "{{cls.name}}", Set[{% for field in cls.fields %} "{{field.name}}", {% endfor %}])
    end
    {% endfor %}

    {% for enum_ in enums if enum_.dynamic %}
    def {{enum_.name}}
        EnumBuilder.new(@registry, "{{enum_.name}}", Set[{% for value in enum_.values %} "{{value.0}}", {% endfor %}])
    end
    {% endfor %}
end
